#include "TrigoBernsteinSurfPopulation.h"
#include "../Core/Constants.h"

using namespace std;

namespace cagd {
    TrigoBernsteinSurfPopulation::Individual::Individual(GLdouble alpha, GLuint n, GLdouble beta, GLuint m,
               Matrix<DCoordinate3> data_net, RowMatrix<GLdouble> u_knot, ColumnMatrix<GLdouble> v_knot,
               GLuint u_div_point, GLuint v_div_point):
        _alpha(alpha), _n(n), _beta(beta), _m(m),
        _data_net_to_interpolate(data_net),
        _u_knot_vector(u_knot),_v_knot_vector(v_knot),
        _u_div_point_count(u_div_point), _v_div_point_count(v_div_point),
        _individual(new TrigonometricBernsteinSurface3(alpha,n,beta,m))
    {
        render();
    }

    TrigoBernsteinSurfPopulation::Individual::Individual(GLdouble alpha, GLuint n, GLdouble beta, GLuint m,
               Matrix<DCoordinate3> data_net,
               GLuint u_div_point, GLuint v_div_point):
        _alpha(alpha), _n(n), _beta(beta), _m(m),
        _data_net_to_interpolate(data_net),
        _u_div_point_count(u_div_point), _v_div_point_count(v_div_point),
        _individual(new TrigonometricBernsteinSurface3(alpha,n,beta,m))
    {
        randomizeUKnots(2 * n + 1);
        randomizeVKnots(2 * n + 1);

        render();
    }

    GLvoid TrigoBernsteinSurfPopulation::Individual::render() {

        if (!_individual)
        {
            throw Exception("Could not create interpolating trigonometric Bernstein like surface!");
        }
        else
        {
            if (!_individual->UpdateDataForInterpolation(_u_knot_vector, _v_knot_vector, _data_net_to_interpolate))
            {
                throw Exception("Could not solve the surface interpolation problem!");
            }
            else
            {
                _fitness = (*_individual).Area(100, 100);
                cout << "The area of the interpolating surface is " << _fitness << endl;
                if (!_individual->UpdateVertexBufferObjectsOfData())
                {
                    throw Exception("Could not create the vertex buffer object of the interpolating surface's control net!");
                }

                _image = _individual->GenerateImage(_u_div_point_count, _v_div_point_count);

                if (!_image)
                {
                    throw Exception("Could not generate the image of the interpolating surface!");
                }
                else
                {
                    if (!_image->UpdateVertexBufferObjects())
                    {
                        throw Exception("Could not create the vertex buffer objects of the interpolating surface's image!");
                    }
                }
            }
        }
    }

    GLboolean TrigoBernsteinSurfPopulation::Individual::randomizeUKnots(GLuint number_of_knots) {
        return GL_FALSE;
    }

    GLboolean TrigoBernsteinSurfPopulation::Individual::randomizeVKnots(GLuint number_of_knots) {
        return GL_FALSE;
    }

    GLboolean TrigoBernsteinSurfPopulation::Individual::calculateLength() {
        _fitness = (*_individual).Area(100, 100);
        return GL_TRUE;
    }

    TrigoBernsteinSurfPopulation::TrigoBernsteinSurfPopulation(GLuint number_of_individuals,
                                GLdouble alpha, GLuint n, GLdouble beta, GLuint m,
                                Matrix<DCoordinate3> data_net,
                                GLuint u_div_point, GLuint v_div_point):
        _data_net_to_interpolate(data_net),
        _number_of_individuals(number_of_individuals)
    {
        if (!number_of_individuals) {
            _individuals.ResizeColumns(0);
        } else {
            _individuals.ResizeColumns(number_of_individuals);

            for (GLuint i = 0; i < number_of_individuals; i++) {
                _individuals[i] = new Individual(alpha, n, beta, m, data_net);
            }

            sort();
            for (GLuint i = 0; i < number_of_individuals; i++) {
                cout << _individuals[i]->getFitness() << endl;
            }
        }
    }

    TrigoBernsteinSurfPopulation::Individual* TrigoBernsteinSurfPopulation::getBest() {
        return _individuals[0];
    }

    RowMatrix<TrigoBernsteinSurfPopulation::Individual*> TrigoBernsteinSurfPopulation::getAllIndividual() {
        return _individuals;
    }

    GLvoid TrigoBernsteinSurfPopulation::sort() {
        return;
    }

    RowMatrix<GLdouble> TrigoBernsteinSurfPopulation::sortUKnots(RowMatrix<GLdouble> knots_vector) {
        return knots_vector;
    }

    ColumnMatrix<GLdouble> TrigoBernsteinSurfPopulation::sortVKnots(ColumnMatrix<GLdouble> knots_vector) {
        return knots_vector;
    }

    TrigoBernsteinSurfPopulation::Individual* TrigoBernsteinSurfPopulation::selection(RowMatrix<Individual*> _individuals) {
        return _individuals[0];
    }

    GLboolean TrigoBernsteinSurfPopulation::mutation() {
        return GL_FALSE;
    }

    GLboolean TrigoBernsteinSurfPopulation::recombination() {
        return GL_FALSE;
    }

    GLvoid TrigoBernsteinSurfPopulation::searchPlace(Individual* best_parent, Individual* worst_parent, Individual* child) {
        return;
    }

    GLvoid TrigoBernsteinSurfPopulation::evolve() {
        return;
    }
}
